# -*- coding: utf-8 -*-
"""
构造/析构相关装饰器定义

本模块提供 constructor/destructor 装饰器，用于在 Python 侧为 C++ 生成标注语义。
装饰器本身不改变函数行为，仅携带元数据，AST 解析时会被收集，
并由 DecoratorSemanticsPass 解释到 IR（IRClassNode.constructor_statements / IRClassNode.destructor_statements）。
"""
from __future__ import annotations
from typing import Any, Callable, Dict, List, Optional, TypeVar, Type, Union, overload


T = TypeVar("T")
F = TypeVar("F", bound=Callable[..., Any])
C = TypeVar("C", bound=Type[Any])


def _passthrough_decorator(meta_name: str, kwargs: Dict[str, Any]) -> Callable[[F], F]:
    """返回一个空操作装饰器，仅附带元数据，供 AST 收集使用。"""

    def _decorator(fn: F) -> F:
        # 运行时不修改行为；元数据由源码层面（AST）解析
        setattr(fn, f"_mcpy_{meta_name}", kwargs)
        return fn

    return _decorator


def constructor(
    *,
    explicit: bool = False,
    noexcept: bool = False,
    defaulted: bool = False,
    deleted: bool = False,
    visibility: str = "public",
    init: Optional[Dict[str, str]] = None,
    base: Optional[List[str]] = None,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    """标注构造函数（须用于 __init__）。

    参数仅作为元数据，实际由生成器读取后输出到 C++。
    """
    meta = {
        "explicit": bool(explicit),
        "noexcept": bool(noexcept),
        "defaulted": bool(defaulted),
        "deleted": bool(deleted),
        "visibility": str(visibility or "public"),
        "init": dict(init or {}),
        "base": list(base or []),
    }
    return _passthrough_decorator("constructor", meta)


def destructor(
    *,
    virtual: bool = True,
    noexcept: bool = False,
    defaulted: bool = False,
    deleted: bool = False,
    visibility: str = "public",
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    """标注析构函数（须用于 __del__）。"""
    meta = {
        "virtual": bool(virtual),
        "noexcept": bool(noexcept),
        "defaulted": bool(defaulted),
        "deleted": bool(deleted),
        "visibility": str(visibility or "public"),
    }
    return _passthrough_decorator("destructor", meta)


def method(
    name: Optional[str] = None,
    *,
    noexcept: bool = False,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    """标注方法（用于导出名称与 noexcept 修饰）。

    - name: 导出别名，不填则使用 Python 方法名
    - noexcept: 生成 C++ 时在声明/定义添加 noexcept
    """
    meta = {
        "name": name,
        "noexcept": bool(noexcept),
    }
    return _passthrough_decorator("method", meta)


def signal(
    name: Optional[str] = None,
    *,
    noexcept: bool = False,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    """标注信号（与 method 类似，允许命名与 noexcept）。"""
    meta = {
        "name": name,
        "noexcept": bool(noexcept),
    }
    return _passthrough_decorator("signal", meta)


"""
MCPy装饰器系统

提供轻量级的装饰器用于标记Python代码，实际的处理逻辑由扩展系统处理。
这些装饰器只负责在代码上添加元数据标记，不包含复杂的处理逻辑。
"""

from typing import Any, List, Optional, TypeVar, Callable, Type


def interface(interface_name: str, doc: str = ""):
    """
    标记类为D-Bus接口

    Args:
        interface_name: D-Bus接口名称，如 "org.example.MyInterface"
        doc: 接口文档说明
    """

    def decorator(cls):
        cls._mcpy_decorator = "interface"
        cls._mcpy_interface_name = interface_name
        cls._mcpy_doc = doc
        return cls

    return decorator


def main() -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    """
    标记函数为程序入口点

    被@main装饰的函数将在生成的C++代码中作为全局命名空间的main函数。

    用法：
        @main
        def main() -> None:
            # 程序入口逻辑
            pass
    """
    return _passthrough_decorator("main", {})


def object(
    object_name: str, path: str, interfaces: Optional[List[str]] = None, doc: str = ""
):
    """
    标记类为D-Bus对象

    Args:
        object_name: D-Bus对象名称
        path: D-Bus对象路径，如 "/org/example/MyObject"
        interfaces: 实现的接口列表
        doc: 对象文档说明
    """

    def decorator(cls):
        cls._mcpy_decorator = "object"
        cls._mcpy_object_name = object_name
        cls._mcpy_path = path
        cls._mcpy_interfaces = interfaces or []
        cls._mcpy_doc = doc
        return cls

    return decorator


# 兼容旧接口：若用户仍从此模块导入 method(doc=...) / signal(doc=...)，
# 可以通过关键字区分，但在我们的 AST 解析中只关心 name/noexcept 元数据


def module(name: str, doc: str = ""):
    """
    标记类为模块声明，name 使用点分隔（如 "mc.protocol"）。
    建议在文件顶层：
        @module("mc.protocol")
        class Module: pass
    可与 @reflectable 结合，通过 module 参数指定归属模块。
    """

    def decorator(cls):
        cls._mcpy_decorator = "module"
        cls._mcpy_module_name = name  # 点分隔名
        cls._mcpy_doc = doc
        return cls

    return decorator


def service(
    service_name: str,
    service_type: str = "singleton",
    auto_start: bool = True,
    doc: str = "",
):
    """
    标记类为可扩展的自定义服务

    Args:
        service_name: 服务名称
        service_type: 服务类型 (singleton, instance, factory)
        auto_start: 是否自动启动
        doc: 服务文档说明
    """

    def decorator(cls):
        cls._mcpy_decorator = "service"
        cls._mcpy_service_name = service_name
        cls._mcpy_service_type = service_type
        cls._mcpy_auto_start = auto_start
        cls._mcpy_doc = doc
        return cls

    return decorator


class field:
    """
    字段描述器，用于标记类属性

    这是一个描述器类，会在类定义时自动收集字段信息。
    """

    def __init__(
        self,
        doc: str = "",
        readonly: bool = False,
        notify_change: bool = False,
        default: Any = None,
    ):
        """
        初始化字段描述器

        Args:
            doc: 字段文档说明
            readonly: 是否只读
            notify_change: 值变化时是否发送通知
            default: 默认值
        """
        self.doc = doc
        self.readonly = readonly
        self.notify_change = notify_change
        self.default = default
        self.name = None

    def __set_name__(self, owner, name):
        """当字段被分配给类属性时调用"""
        self.name = name

        # 在类上添加字段元数据
        if not hasattr(owner, "_mcpy_fields"):
            owner._mcpy_fields = {}

        owner._mcpy_fields[name] = {
            "doc": self.doc,
            "readonly": self.readonly,
            "notify_change": self.notify_change,
            "default": self.default,
        }

    def __get__(self, obj, objtype=None):
        """获取字段值"""
        if obj is None:
            return self
        return getattr(obj, f"_{self.name}", self.default)

    def __set__(self, obj, value):
        """设置字段值"""
        if self.readonly:
            raise AttributeError(f"字段 '{self.name}' 是只读的")
        setattr(obj, f"_{self.name}", value)


# 为了向后兼容，保留一些别名
Field = field


def computed_property(name: str | None = None):
    """
    标记计算属性的 getter，用于导出为反射属性/DBus 属性。
    - name: 可选别名；不提供则使用属性名
    用法：
      @computed_property("Id")
      @property
      def id(self) -> int: ...
      @id.setter
      def id(self, v: int) -> None: ...
    注意：此装饰器返回 property，以便与 @property/@<prop>.setter 链式工作。
    生成器将基于 AST 识别并收集 getter/setter。
    """

    def _decorator(func):
        # 在函数对象上记录元数据，便于 AST/运行期调试；实际解析依赖 AST
        setattr(func, "_mcpy_decorator", "computed_property")
        setattr(func, "_mcpy_property_name", name)
        return property(func)

    return _decorator


T = TypeVar("T")
F = TypeVar("F", bound=Callable[..., Any])


@overload
def export(
    macro: str = "MC_API",
    *,
    name: Optional[str] = None,
) -> Callable[[F], F]:
    """函数装饰器重载"""
    ...


@overload
def export(
    macro: str = "MC_API",
    *,
    name: Optional[str] = None,
) -> Callable[[C], C]:
    """类装饰器重载"""
    ...


def export(
    macro: str = "MC_API",
    *,
    name: Optional[str] = None,
) -> Union[Callable[[F], F], Callable[[C], C]]:
    """
    标记函数/方法为导出API（替代@mc_api装饰器）。

    Args:
        macro: 导出宏名称，默认为"MC_API"
        name: 可选的导出别名，不填则使用原函数名
    """
    meta = {
        "macro": macro,
        "name": name,
    }
    return _passthrough_decorator("export", meta)


def namespace(name: str = ""):
    """
    标记类或函数属于指定的C++命名空间。

    Args:
        name: 命名空间名称，支持点分隔的嵌套命名空间（如 "company.project.utils"）
              空字符串或None表示全局作用域

    用法：
        @namespace("utilities")
        class Utils:
            pass

        @namespace("company.project.utils")
        class DatabaseHelper:
            pass

        @namespace()  # 全局作用域
        def main() -> int:
            pass
    """
    meta = {
        "name": name,
    }
    return _passthrough_decorator("namespace", meta)


def extern_c():
    """
    标记函数为C兼容函数，生成extern "C"声明。

    用法：
        @extern_c()
        def c_compatible_function() -> int:
            pass
    """
    return _passthrough_decorator("extern_c", {})


def reflectable(name: str, module: Any | None = None):
    """
    标记普通类为可反射（等价 C++ 的 MC_REFLECTABLE("Name")）。
    - name: 反射导出名
    - module: 可选，模块声明类（@module 装饰后的类）或点分隔名（如 "mc.protocol"），用于将该类归属到某模块
    """

    def decorator(cls):
        cls._mcpy_decorator = "reflectable"
        cls._mcpy_reflect_name = name
        if module is not None:
            # 支持传入模块类或字符串名称
            mod_name = None
            try:
                # 装饰过的模块类上会有 _mcpy_module_name
                mod_name = getattr(module, "_mcpy_module_name", None)
            except Exception:
                mod_name = None
            if mod_name is None and isinstance(module, str):
                mod_name = module
            if mod_name:
                cls._mcpy_module_name = mod_name
        return cls

    return decorator
